#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include <sqlite3.h>

#define TABLE_NAME "RPI_num2"


sqlite3     *db;
char        *zErrMsg;
int         rc;
int         iTableExist=0;
int         clifd;


static int callback(void *NotUsed, int argc, char **argv, char **azColName);
void  sqlite_init(void);
void sqlite_create_table(char *table_name);
void sqlite_insert(char *buftok[], char *table_name);
int sqlite_table_exist(char *table_name);
static int table_exist_callback(void *data, int argc, char **argv, char **azColName);


void print_usage(char *progname)
{
	printf("%s usage: \n", progname);
	printf("-p(--port): sepcify server listen port.\n");
	printf("-h(--Help): print this help information.\n"); return ;
}

int main(int argc, char **argv)
{
	int            sockfd = -1;
	int            rv = -1;
	struct         sockaddr_in servaddr;
	struct         sockaddr_in cliaddr;
	socklen_t      len=sizeof(struct sockaddr);
	int            port = 0;
	int            ch;
	int            on = 1;
	int            j=0;
	char           *p;
	char           *pos;
	char           *buftok[3];
	pid_t          pid;
	struct         option opts[] = {
		{"port", required_argument, NULL, 'p'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};


	while( (ch=getopt_long(argc, argv, "p:h", opts, NULL)) != -1 )
	{
		switch(ch)
		{
			case 'p':
				port=atoi(optarg);
				break;
			case 'h':
				print_usage(argv[0]);
				return 0;
		}
	}


	if( !port )
	{
		print_usage(argv[0]);
		return 0;
	}


	sockfd=socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("Create socket failure: %s\n", strerror(errno));
		return -1;
	}
	printf("Create socket[%d] successfully!\n", sockfd);

	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	servaddr.sin_port = htons(port);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);/* listen all the IP address on this host */

	
	rv=bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	if(rv < 0)
	{
		printf("Socket[%d] bind on port[%d] failure: %s\n", sockfd, port, strerror(errno));
		return -2;
	}

	listen(sockfd, 13);
	printf("Start to listen on port [%d]\n", port);


	sqlite_init();
	if(sqlite_table_exist(TABLE_NAME) == 0)
	{
		sqlite_create_table(TABLE_NAME);
	}

	while(1)
	{
		printf("Start accept new client incoming...\n");
		clifd=accept(sockfd, (struct sockaddr *)&cliaddr, &len);
		if(clifd < 0)
		{
			printf("Accept new client failure: %s\n", strerror(errno));
			continue;
		}
		printf("Accept new client[%s:%d] successfully\n", inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
		
		pid = fork();
		if( pid < 0 )
		{
			printf("fork() create child process failure: %s\n", strerror(errno));
			close(clifd);
			continue;
		}

		else if( pid > 0 )
		{
			/* Parent process close client fd and goes to accept new socket client again */
			close(clifd);
			continue;
		}
		else if ( 0 == pid )
		{
			char buf[1024];
			printf("Child process start to commuicate with socket client...\n");
			close(sockfd); /* Child process close the listen socket fd */

			while(1)
			{
				memset(buf, 0, sizeof(buf));
				rv=read(clifd, buf, sizeof(buf));
				if( rv < 0 )
				{
					printf("Read data from client sockfd[%d] failure: %s\n", clifd,strerror(errno));
					close(clifd);
					exit(0);
				}
				else if( rv == 0) 
				{
					printf("Socket[%d] get disconnected\n", clifd);
					close(clifd);
					exit(0);
				}
				else if( rv > 0 )
				{
					printf("Read %d bytes data from Server: %s\n", rv, buf);
				}

				rv=write(clifd, buf, rv);
				if(rv < 0)
				{
					printf("Write to client by sockfd[%d] failure: %s\n", clifd,strerror(errno));
					close(clifd); 
					exit(0);
				}


				p=strtok(buf,"/");
				while(p != NULL && j<3)
				{
					buftok[j]=p;
					p=strtok(NULL,"/");
					j++;
				}

				pos=strtok(buftok[1],"/");
				if(pos != NULL)
				{
					buftok[1]=pos;
				}

				if(sqlite_table_exist(TABLE_NAME)>0)
				{
					sqlite_init();
					sqlite_insert(buftok,TABLE_NAME);
				}
				else
				{
					sqlite_init();
					sqlite_create_table(TABLE_NAME);
					sqlite_insert(buftok,TABLE_NAME);
				}
			} /* Child process loop */
		} /* Child process start*/
	}
	return 0;
}


void sqlite_insert(char *buftok[], char *table_name)
{
	char   sql_buffer[512];
	char   *SN1 = buftok[0];
	char   *DATIME1 = buftok[1];
	char   *TEMPERATURE1 = buftok[2];

	memset(sql_buffer,0,sizeof(sql_buffer));
	printf("Accept client[%d] data successfully!\n", clifd);

	snprintf(sql_buffer,512, "INSERT INTO %s VALUES ('%s', '%s', '%s');" ,table_name, SN1, DATIME1, TEMPERATURE1);
	rc = sqlite3_exec(db, sql_buffer, callback, 0, &zErrMsg);
	if( rc != SQLITE_OK )
	{
		printf("sqlite_insert: %s\n", zErrMsg);
		sqlite3_free(zErrMsg);
	}
	else
	{
		printf("Records created successfully\n");
	}
	return;
}



int sqlite_table_exist(char *table_name)
{
	char   table_exist[512];

	memset(table_exist,0,sizeof(table_exist));
	snprintf(table_exist,512,"SELECT COUNT(*) FROM sqlite_master where type ='table' and name ='%s';", table_name);
	rc = sqlite3_exec(db, table_exist, table_exist_callback, 0, &zErrMsg);
	if(rc != SQLITE_OK)
	{
		printf("sqlite_table_exist:%s\n", zErrMsg);
		sqlite3_free(zErrMsg);
		exit(0);
	}

	if(iTableExist)
	{
		printf("%s is exist!\n", table_name);
		return iTableExist;
	}
	else
	{
		return iTableExist;
	}
}



static int table_exist_callback(void *data, int argc, char **argv, char **azColName)
{
	if ( 1 == argc)
	{
		iTableExist = atoi(*(argv));
	}
	return 0; 
}



void sqlite_create_table(char *table_name)
{
	char create_table[100];

	memset(create_table,0,sizeof(create_table));
	snprintf(create_table,100,"CREATE TABLE %s(SN CHAR(10),DATIME CHAR(50),TEMPERATURE CHAR(10));", table_name);
	rc = sqlite3_exec(db, create_table, callback, 0, &zErrMsg);
	if(rc != SQLITE_OK)
	{
		printf("sqlite_create_table:%s\n", zErrMsg);
		sqlite3_free(zErrMsg);
		exit(0);
	}
	else
	{
		printf("Table created successfully!\n");
	}
	return;
}



static int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
	int i;
	for(i=0; i<argc; i++)
	{
		printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
	}
	printf("\n");
	return 0;
}



void  sqlite_init(void)
{
	rc = sqlite3_open("RPI_temperature2.db", &db);
	if(rc)
	{
		printf("Can't open database:%s\n", sqlite3_errmsg(db));
		exit(0);
	}
	else
	{
		printf("Opened database successfully\n");
	}	
}
